package framework.classification.library;

import framework.AnnuaireCocola;
import framework.HierarchyCocola;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

import org.eclipse.emf.common.util.EList;

import cocola.Component;
import cocola.Interface;
import cocola.Operation;


import framework.classification.entities.ClAbstractEntity;
import framework.classification.entities.ClComponent;
import framework.classification.entities.ClFunctionProvided;
import framework.classification.entities.ClFunctionRequired;
import framework.classification.entities.ClInterfaceProvided;
import framework.classification.entities.ClInterfaceRequired;
import framework.classification.entities.lattice.erca.LatticeComponentErca;
import framework.classification.entities.lattice.erca.LatticeFunctionProvidedErca;
import framework.classification.entities.lattice.erca.LatticeFunctionRequiredErca;
import framework.classification.entities.lattice.erca.LatticeInterfaceProvidedErca;
import framework.classification.entities.lattice.erca.LatticeInterfaceRequiredErca;
import framework.entity.ACLComponent;
import framework.entity.ACLEntity;
import framework.entity.ACLFunction;
import framework.entity.ACLInterface;
import framework.io.out.LatticeToImage;
import framework.io.out.TableToLatex;


public class SmartClassfication extends AbstractClassfication{


	public int niv;
	
	public static String MODE = "SMART_NIV";

	public static int NIV1 = 0;
	
	public static int NIV2 = 1;
	
	public SmartClassfication(HierarchyCocola structure, AnnuaireCocola coco,String latticeGeneration) {
		super(structure, coco,latticeGeneration);

	}
	
	public SmartClassfication(HierarchyCocola structure, AnnuaireCocola coco,int niv,String latticeGeneration) {
		super(structure, coco,latticeGeneration);
		this.niv = niv;

	}

	


	public String getmode() {
	
		return (MODE+niv);
	}



	public void computeClassification(){

		computeFunctionClassfication2();
		computeInterfaceClassification2();
		computeComponentClassification();

	}

	public void computeComponentClassification() {

		ArrayList<ArrayList<String>> partitions = null;
		
		if (this.niv == this.NIV1)
			partitions = getConnexeElement(
						getStructure().getComponentstoFunctions(),
						getStructure().getFunctionstoComponents());
		else if (this.niv == this.NIV2)
			partitions = cut(
					getStructure().getComponentsToInterface(),
					getStructure().getInterfacesToComponent());


		for (ArrayList<String> p : partitions){
			//on recupere la definition de tous les composants de la structure
			//dans la liste listcompo
			ArrayList<ACLComponent> listcompo = new ArrayList<ACLComponent>();
			
			for (String compo : p){
				ACLComponent aclcompo = new ACLComponent(compo);
				ArrayList<ACLInterface> intersPro = getStructure().getComponentsProvided().get(aclcompo.getName());
				ArrayList<ACLInterface> intersReq  = getStructure().getComponentsRequired().get(aclcompo.getName());
				for (ACLInterface  aclinter : intersPro){
					aclcompo.addInterfacePro(aclinter);
				}
				for (ACLInterface  aclinter : intersReq){
					aclcompo.addInterfaceReq(aclinter);
				}
				listcompo.add(aclcompo);
			}



			ClComponent cl = new ClComponent(getLatticeGeneration()+niv+"_Component"+clComponents.size(),this,new LatticeComponentErca(),listcompo);
			cl.computeRelation();
			cl.computeLattice();
			clComponents.add(cl);


			//on recupere tous les composants reel
			for (String ent : cl.getRealReduced().keySet()){
				ACLComponent aclcompo = new ACLComponent(ent,ACLFunction.MODE2);

				if (!components.containsKey(aclcompo.getName()))
					components.put(aclcompo.getName(),new ArrayList<ClAbstractEntity>());

				if (!componentsName.containsKey(aclcompo.getName()))
					componentsName.put(aclcompo.getName(),aclcompo);

				components.get(aclcompo.getName()).add(cl);
			}

			//on reccupere tous les composants abstrait
			for (String ent : cl.getAbstractReduced().keySet()){
				ACLComponent aclcompo = new ACLComponent(ent,ACLFunction.MODE2);

				if (!components.containsKey(aclcompo.getName()))
					components.put(aclcompo.getName(),new ArrayList<ClAbstractEntity>());

				if (!componentsName.containsKey(aclcompo.getName()))
					componentsName.put(aclcompo.getName(),aclcompo);

				components.get(aclcompo.getName()).add(cl);


			}
		}
	}

	//=================================================
	//=== Composantes Smart
	//=================================================
	// Entree : 2 hasmap formant un graphe biparti
	// Sortie : une liste de sous ensemble formant des composantes connexes


	public ArrayList<ArrayList<String>> cut(
			HashMap<String, ArrayList<String>> part1,
			HashMap<String, ArrayList<String>> part2) {

		ArrayList<ArrayList<String>> array = new ArrayList<ArrayList<String>>();

		for (String inter : part2.keySet()) {

			String role = inter.substring(0, 3);
			String interName = inter.substring(4);
			ClAbstractEntity model = null;
			ArrayList<String> list = new ArrayList<String>();

			if (role.equals("PRO")) {
				model = getInterfacesProvided().get(interName);
				for (String interX : model.getEntity()) {
					if (part2.containsKey("PRO-" + interX)) {
						for (String compo : part2.get("PRO-" + interX)) {
							if (!list.contains(compo))
								list.add(compo);
						}
					}

				}
			} else {
				model = getInterfacesRequired().get(interName);
				for (String interX : model.getEntity()) {
					if (part2.containsKey("REQ-" + interX)) {
						for (String compo : part2.get("REQ-" + interX)) {
							if (!list.contains(compo))
								list.add(compo);
						}
					}

				}
			}

			array.add(list);
		}

		return parse(array);

	}

	public ArrayList<ArrayList<String>> parse(ArrayList<ArrayList<String>> list) {
		ArrayList<ArrayList<String>> result = new ArrayList<ArrayList<String>>();
		for (ArrayList<String> l1 : list) {
			Boolean add = true;

			for (ArrayList<String> l2 : result) {
				if (l1.size() >= l2.size()) {
					if (l1.containsAll(l2)) {
						l2.removeAll(l2);
					}
				} else {
					if (l2.containsAll(l1)) {
						add = false;
					}
				}
			}
			if (add)
				result.add(l1);
		}

		ArrayList<ArrayList<String>> results = new ArrayList<ArrayList<String>>();
		for (ArrayList<String> l1 : result) {
			if (l1.size() > 0)
				results.add(l1);
		}
		return results;
	}
	//==============================================================
	//=== Fin Composante Smart
	//==============================================================





	









}
